from urllib.parse import urlencode, urljoin

from django.contrib.auth import REDIRECT_FIELD_NAME, authenticate
from django.contrib.auth import login as django_login
from django.contrib.auth import logout as django_logout


def _get_user(request, service, ticket):
    return authenticate(request=request, ticket=ticket, service=service)


def _login_user(request, user):
    django_login(request, user)


def _logout_user(request):
    django_logout(request)


def _service_url(request, redirect_to=None):
    """Generates application service URL for CAS"""

    protocol = ("http://", "https://")[request.is_secure()]
    host = request.get_host()
    service = protocol + host + request.path
    if redirect_to:
        if "?" in service:
            service += "&"
        else:
            service += "?"
        service += urlencode({REDIRECT_FIELD_NAME: redirect_to})
    return service


def _redirect_url(request, settings):
    """Redirects to referring page, or CAS_REDIRECT_URL if no referrer is
    set.
    """

    _next = request.GET.get(REDIRECT_FIELD_NAME)
    if not _next:
        if settings.CAS_IGNORE_REFERER:
            _next = settings.CAS_REDIRECT_URL
        else:
            _next = request.META.get("HTTP_REFERER", settings.CAS_REDIRECT_URL)
        prefix = ("http://", "https://")[request.is_secure()] + request.get_host()
        if _next.startswith(prefix):
            _next = _next[len(prefix) :]
    return _next


def _login_url(service, settings):
    """Generates CAS login URL"""

    params = {"service": service}
    if settings.CAS_EXTRA_LOGIN_PARAMS:
        params.update(settings.CAS_EXTRA_LOGIN_PARAMS)
    return urljoin(settings.CAS_SERVER_URL, "login") + "?" + urlencode(params)


def _logout_url(request, settings, next_page=None):
    """Generates CAS logout URL"""

    url = urljoin(settings.CAS_SERVER_URL, "logout")
    if next_page:
        protocol = ("http://", "https://")[request.is_secure()]
        host = request.get_host()
        url += "?" + urlencode({"url": protocol + host + next_page})
    return url


def login_user(request, settings, next_page, required):
    if not next_page:
        next_page = _redirect_url(request, settings)
    if request.user.is_authenticated:
        return next_page, None

    ticket = request.GET.get("ticket")
    service = _service_url(request, next_page)

    if ticket:
        user = _get_user(ticket=ticket, service=service, request=request)

        if user is not None:
            _login_user(request, user)
            return next_page, None
        elif settings.CAS_RETRY_LOGIN or required:
            login_url = _login_url(service, settings)
            return login_url, None
        else:
            return "", "general_login_error"
    else:
        login_url = _login_url(service, settings)
        return login_url, None


def logout_user(request, settings, next_page):
    _logout_user(request)
    if not next_page:
        next_page = _redirect_url(request, settings)
    if settings.CAS_LOGOUT_COMPLETELY:
        complete_logout_page = _logout_url(request, settings, next_page)
        return complete_logout_page
    else:
        return next_page
